package com.zenithmind.user.security.impl;

import com.zenithmind.user.security.PasswordEncoder;
import lombok.extern.slf4j.Slf4j;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.stereotype.Component;

import java.util.regex.Pattern;

/**
 * BCrypt密码编码器实现
 * 遵循单一职责原则：专门负责BCrypt算法的密码处理
 * 遵循开闭原则：实现接口，便于扩展其他加密算法
 */
@Slf4j
@Component
public class BCryptPasswordEncoder implements PasswordEncoder {
    
    private static final int DEFAULT_ROUNDS = 12;
    
    // 密码强度验证正则表达式
    private static final Pattern WEAK_PATTERN = Pattern.compile("^.{1,7}$");
    private static final Pattern MEDIUM_PATTERN = Pattern.compile("^(?=.*[a-z])(?=.*[A-Z]).{8,}$");
    private static final Pattern STRONG_PATTERN = Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$");
    private static final Pattern VERY_STRONG_PATTERN = Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&]).{8,}$");
    
    @Override
    public String encode(String rawPassword) {
        if (rawPassword == null) {
            throw new IllegalArgumentException("密码不能为空");
        }
        
        try {
            String encoded = BCrypt.hashpw(rawPassword, BCrypt.gensalt(DEFAULT_ROUNDS));
            log.debug("密码加密成功");
            return encoded;
        } catch (Exception e) {
            log.error("密码加密失败: {}", e.getMessage());
            throw new RuntimeException("密码加密失败", e);
        }
    }
    
    @Override
    public boolean matches(String rawPassword, String encodedPassword) {
        if (rawPassword == null || encodedPassword == null) {
            log.warn("密码验证失败: 密码或加密密码为空");
            return false;
        }
        
        try {
            boolean matches = BCrypt.checkpw(rawPassword, encodedPassword);
            log.debug("密码验证结果: {}", matches ? "成功" : "失败");
            return matches;
        } catch (IllegalArgumentException e) {
            log.warn("密码验证失败: {}", e.getMessage());
            return false;
        } catch (Exception e) {
            log.error("密码验证异常: {}", e.getMessage());
            return false;
        }
    }
    
    @Override
    public PasswordStrength checkStrength(String password) {
        if (password == null || password.isEmpty()) {
            return PasswordStrength.WEAK;
        }
        
        if (VERY_STRONG_PATTERN.matcher(password).matches()) {
            return PasswordStrength.VERY_STRONG;
        } else if (STRONG_PATTERN.matcher(password).matches()) {
            return PasswordStrength.STRONG;
        } else if (MEDIUM_PATTERN.matcher(password).matches()) {
            return PasswordStrength.MEDIUM;
        } else {
            return PasswordStrength.WEAK;
        }
    }
    
    /**
     * 验证密码是否满足最低强度要求
     */
    public boolean isPasswordValid(String password) {
        PasswordStrength strength = checkStrength(password);
        return strength.getLevel() >= PasswordStrength.MEDIUM.getLevel();
    }
    
    /**
     * 生成随机密码
     */
    public String generateRandomPassword(int length) {
        if (length < 8) {
            throw new IllegalArgumentException("密码长度不能少于8位");
        }
        
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$!%*?&";
        StringBuilder password = new StringBuilder();
        
        // 确保包含各种字符类型
        password.append(getRandomChar("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); // 大写字母
        password.append(getRandomChar("abcdefghijklmnopqrstuvwxyz")); // 小写字母
        password.append(getRandomChar("0123456789")); // 数字
        password.append(getRandomChar("@$!%*?&")); // 特殊字符
        
        // 填充剩余长度
        for (int i = 4; i < length; i++) {
            password.append(getRandomChar(chars));
        }
        
        // 打乱字符顺序
        return shuffleString(password.toString());
    }
    
    private char getRandomChar(String chars) {
        return chars.charAt((int) (Math.random() * chars.length()));
    }
    
    private String shuffleString(String str) {
        char[] chars = str.toCharArray();
        for (int i = chars.length - 1; i > 0; i--) {
            int j = (int) (Math.random() * (i + 1));
            char temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
        }
        return new String(chars);
    }
}
